package dimension.starry.Tasks;

import net.minecraft.entity.Entity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;

import java.util.Vector;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TaskManager {

    private static final ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(20);
    private static final Vector<Runnable> tasks = new Vector<>();
    private static final ConcurrentLinkedQueue<Entity> removeEntities = new ConcurrentLinkedQueue<Entity>();
    private static final ConcurrentLinkedQueue<Entity> addEntities = new ConcurrentLinkedQueue<Entity>();
    private static final ConcurrentLinkedQueue<World> addWorld = new ConcurrentLinkedQueue<World>();
    private static final Lock lock = new ReentrantLock();

    public static void addTask(Runnable runnable) {
        tasks.add(runnable);
    }

    public static void removeTask(Runnable runnable) {
        tasks.remove(runnable);
    }

    public static void onServerStarted(MinecraftServer server) {
        scheduledThreadPool.scheduleWithFixedDelay(
            () -> tasks.forEach(scheduledThreadPool::execute), 1000L, 1000L, TimeUnit.MILLISECONDS
        );
    }

    public static void onStartTick(MinecraftServer server) {
        if (!removeEntities.isEmpty()) {
            Entity entity = removeEntities.poll();
            if (entity != null) {
                entity.remove(Entity.RemovalReason.DISCARDED);
            }
        }

        if (!addEntities.isEmpty()) {
            if (lock.tryLock()) {
                Entity entity = addEntities.poll();
                World world = addWorld.poll();
                lock.unlock();
                world.spawnEntity(entity);
            }
        }
    }

    public static void removeEntity(Entity entity) {
        removeEntities.add(entity);
    }

    public static void addEntity(Entity entity, World world) {
        try {
            lock.lock();
            addEntities.add(entity);
            addWorld.add(world);
        } finally {
            lock.unlock();
        }
    }

}
